package com.gwtjs.icustom.controller.install;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;

import com.gwtjs.icustom.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.gwtjs.icustom.construct.AppConstruct;
import com.gwtjs.icustom.construct.AppTypeConstruct;
import com.gwtjs.icustom.entity.ResultWrapper;
import com.gwtjs.icustom.entity.SSHClientVO;
import com.gwtjs.icustom.mapper.AppMapper;
import com.gwtjs.icustom.mapper.ServerHostMapper;
import com.gwtjs.icustom.pojo.App;
import com.gwtjs.icustom.pojo.ServerHost;

@RestController
@RequestMapping("/install")
public class InstallAppController {

	private final static Logger logger = LoggerFactory.getLogger(SetSystemController.class);
	
	@Value("${app.work.home}")
	private String workHome;
	@Value("${httpd.server.port}")
	private String httpPort;
	@Value("${ambari.db.port}")
	private String ambariDBPort;
	@Value("${ambari.db.username}")
	private String ambariDBUsername;
	@Value("${ambari.db.password}")
	private String ambariDBPassword;
	
	//脚本启动docker使用root帐户
	@Value("${root.db.password}")
	private String rootDBPassword;
	@Value("${ambari.db.driver}")
	private String ambariDBDriver;

	@Autowired
	private AppMapper appMapper;
	@Autowired
	private ServerHostMapper serverHostMapper;
	
	@PutMapping("/autoInstall")
	public ResultWrapper autoInstall(@RequestBody App app) throws Exception {
		
		ServerHost host=serverHostMapper.queryHostByIp(app.getAppIp());

		logger.info("\n安装到主机 ：{}" , app.getAppIp());
		
		List<ServerHost> records = new ArrayList<ServerHost>();
		records.add(host);
		ResultWrapper result = this.dockerInstall(records);
		logger.info("\n安装到主机 ：{} , 检查 docker:{}" , app.getAppIp(),result);
		
		if(app.getAppName().equals(AppConstruct.HTTPD_APP)) {
			this.httpdInstall(host);
		}else {
			this.mysqlInstall(host);
		}
		app.setAppType(AppTypeConstruct.APP_TOOL);
		List<App> appList = appMapper.queryAppList(app);
		return ResultWrapper.constructSuccessResult("SUCCESS",appList);
		
	}

	/**
	 * <h2>安装httpd</h2>
	 * <p><h1>拼接shell命令待优化</h1>
	 * <h1>分发 repo 待优化</h1>
	 * <h3>分为三步</h3>
	 * <ul>
	 * <ol>
	 * <li>发送docker备份安装文件和安装脚本到指定主机</li>
	 * <li>解压文件</li>
	 * <li>执行安装脚本.sh</li>
	 * <li>拷贝安装包到httpd启动目录的doc下</li>
	 * <li>修改*.repo文件的baseurl</li>
	 * <li>执行cd httpd_path/doc/ && createrepo .</li>
	 * </ol>
	 * </ul>
	 * </p>
	 * @throws IOException 
	 * */
	@PutMapping("/httpd")
	public ResultWrapper httpdInstall(@RequestBody ServerHost server) throws Exception {
		String cmd = "ip addr";
		ShellUtil execute = null;
		String result = null;
		final String remote = "/opt";
		final String httpdVersion="2.4.57-alpine";
		final String appHome = String.format("%s/httpd-%s", remote,httpdVersion);
		final String fileName = String.format("httpd-%s.tar.gz", httpdVersion);
		
		final String local = String.format("%s/app/%s", workHome,fileName);
		final String shName = "httpd-start.sh";
		SSHClientVO clientVO = null;
		
		App app = new App();
		app.setAppIp(server.getHostIp());
		app.setAppName(AppConstruct.HTTPD_APP);
		app.setAppType(AppTypeConstruct.APP_TOOL);

		execute = new ShellUtil(server.getHostIp(), server.getAccount(), server.getPassword(), server.getHostPort());
		
		//将安装文件压缩包分发到集群各主机
		clientVO = JScpUtil.upload(server, local, remote);
		logger.info("\n httpd安装包是否发送成功，请验证 1 ：{} {}\n" , server.getHostIp(),remote);
		
		cmd = String.format("cd %s && tar -zxvf %s && rm -rf %s", remote,fileName,fileName);
		result = execute.executeForResult(cmd);
		logger.info("\n解压http安装包 1 \ncmd ：{} \nresult: {}\n" ,cmd, result);
		
		cmd = String.format("cd %s && chmod 755 %s", appHome,shName);
		result = execute.executeForResult(cmd);
		logger.info("\nhttp安装脚本授权755 2 cmd ：{}\n" , result);
		
		cmd = String.format("cd %s && sed -i 's/template_port/%s/g' %s", appHome,httpPort,shName);
		result = execute.executeForResult(cmd);
		logger.info("\n安装执行{} cmd ：{}\n" , cmd,result);
		
		cmd = String.format("cd %s && ./%s", appHome,shName);
		result = execute.executeForResult(cmd);
		logger.info("\n安装执行{} cmd ：{}\n" , cmd,result);
		
		//开始拷贝安装源及yum repo -->
		cmd = String.format("\\cp -rf /etc/yum.repos.d /root/yum.repos.d.bak && cd /etc/yum.repos.d && rm -rf ./*", appHome,shName);
		result = execute.executeForResult(cmd);
		logger.info("\n安装执行{} 请验证/etc/yum.repos.d目录下文件是否已清除 ：{}\n" , shName,result);
		
		final String yumPkg = "ambari-2.7.5.0-72.tar.gz,HDP.tar.gz,HDP-UTILS.tar.gz,local-yum.tar.gz";//
		final String[] pkgs = yumPkg.split(",");
		final String httpDocPkgPath = String.format("%s/doc",appHome);
		
		for (String pkg : pkgs) {
			String yumPkgPath = String.format("%s/yum-pkg/%s", workHome,pkg);
			JScpUtil.upload(server, yumPkgPath, httpDocPkgPath);
			logger.info("\n {} 安装包是否发送成功，请验证主机{}： {}\n" , pkg,server.getHostIp(),appHome);
			//解压文件,清理压缩包
			cmd = String.format("cd %s && tar -zxvf %s && rm -rf %s", httpDocPkgPath,pkg,pkg);
			logger.info("\n 主机{}:路径：{} {}解压文件成功否，{} 清理文件，\n请验证语句:{}\n" , server.getHostIp(),appHome,pkg,pkg,cmd);
			result = execute.executeForResult(cmd);

		}

		execute.close();

		//将httpd.ambari添加到各主机hosts
		this.installHosts(server.getHostIp(),AppConstruct.HTTPD_APP);
		server.setIsHttpdFlag(1);
		app.setPort(httpPort);
		serverHostMapper.updateAppStatus(server);

		app.setAppDockerPath(appHome);
		executeAppData(app ,server);

		this.synYum(clientVO);
		
		return ResultWrapper.successResult();

	}
	
	/**
	 * <h2>安装mysql</h2>
	 * <p><h3>分为三步</h3>
	 * <ul>
	 * <ol>
	 * <li>发送docker备份和安装脚本到指定主机</li>
	 * <li>解压文件</li>
	 * <li>执行安装脚本.sh</li>
	 * </ol>
	 * </ul>
	 * </p>
	 * @throws IOException 
	 * */
	@PutMapping("/mysql")
	public ResultWrapper mysqlInstall(@RequestBody ServerHost server) throws Exception {
		
		String cmd = "ip addr";
		ShellUtil execute = null;
		String result = null;
		final String remote = "/opt";
		final String mysqlVersion="5.7.42-oracle";
		final String appHome = String.format("%s/mysql-%s", remote,mysqlVersion);
		final String fileName = String.format("mysql-%s.tar.gz", mysqlVersion);
		final String local = String.format("%s/app/%s", workHome,fileName);
		final String shName = "mysql-start.sh";
		
		App app = new App();
		app.setAppIp(server.getHostIp());
		app.setAppName(AppConstruct.MYSQL_APP);
		app.setAppType(AppTypeConstruct.APP_TOOL);

		execute = new ShellUtil(server.getHostIp(), server.getAccount(), server.getPassword(), server.getHostPort());
		
		cmd = String.format("cd %s && rm -rf %s", remote,appHome);
		result = execute.executeForResult(cmd);
		logger.info("\n清除docker历史安装目录 0 cmd ：{}" , result);
		
		//将安装文件压缩包分发到集群各主机
		JScpUtil.upload(server, local, remote);
		
		cmd = String.format("cd %s && tar -zxvf %s && rm -rf %s", remote,fileName,fileName);
		result = execute.executeForResult(cmd);
		logger.info("\n解压http安装包 1 cmd ：{}" , result);
		
		//这个地方做改动，将shell脚本的密码及端口(13308)参数改掉
		cmd = String.format("cd %s && sed -i 's/13308/%s/g' %s", appHome,ambariDBPort,shName);
		logger.info("\n更换端口 cmd ：{}" , cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n更换端口 2 cmd ：{}" , result);
		
		//这个地方做改动，将shell脚本的密码(rootroot123)及端口(13308)参数改掉
		cmd = String.format("cd %s && sed -i 's/rootroot123/%s/g' %s", appHome,rootDBPassword,shName);
		logger.info("\n更换密码 cmd ：\n{}" , cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n更换密码 2 cmd ：\n{}\n" , result);
		
		cmd = String.format("cd %s && chmod 755 %s", appHome,shName);
		result = execute.executeForResult(cmd);
		logger.info("\nhttp安装脚本授权755 2 cmd ：{}" , result);
		
		cmd = String.format("cd %s && ./%s", appHome,shName);
		result = execute.executeForResult(cmd);
		logger.info("\n安装执行{} cmd ：{}" , shName,result);

		//将mysql.ambari添加到各主机hosts
		this.installHosts(server.getHostIp(),AppConstruct.MYSQL_APP);

		server.setIsSqlFlag(1);
		serverHostMapper.updateAppStatus(server);
		
		logger.info("\n验证mysql安装并写入应用库 ：" );

		app.setUsername(ambariDBUsername);
		app.setPassword(ambariDBPassword);
		app.setPort(ambariDBPort);
		app.setDriver(ambariDBDriver);
		app.setAppDockerPath(appHome);
		executeAppData(app ,server);

		logger.info("\n插入数据到应用表 ：{}" , result);
		execute.close();
		return ResultWrapper.successResult(app);
	}

	/**是新增还是修改*/private void executeAppData(App app ,ServerHost server){
		Integer appCount = appMapper.queryByNameAndIpCount(app);
		logger.info("\n httpd应用统计： {}\n" , appCount);

		app.setAppFlag(1);
		if(appCount>0) {
			appMapper.updateApp(app);
		}else {
			appMapper.addApp(app);
		}
	}
	
	/**
	 * <h2>安装docker</h2>
	 * <p><h3>分为三步</h3>
	 * <ul>
	 * 	<ol>
	 * <li>发送安装文件到指定主机</li>
	 * <li>解压文件</li>
	 * <li>执行安装脚本.sh</li>
	 * </ol>
	 * </ul>
	 * </p>
	 * @param records
	 * @return
	 * @throws Exception
	 */
	@PutMapping("/docker")
	public ResultWrapper dockerInstall(@RequestBody List<ServerHost> records) throws Exception {
		App app = null;
		String cmd = "ip addr";
		ShellUtil execute = null;
		String result = null;
		final String remote = "/opt";
		final String dockerVersion="20.10.24";
		final String fileName = String.format("docker-%s.tar.gz", dockerVersion);
		final String appHome = String.format("%s/docker-%s", remote,dockerVersion);
		final String local = String.format("%s/app/%s", workHome,fileName);
		final String shName = "install_docker.sh";
		
		for (ServerHost host : records) {
			app = new App();
			app.setAppIp(host.getHostIp());
			app.setAppName(AppConstruct.DOCKER_APP);
			app.setAppType(AppTypeConstruct.APP_TOOL);

			execute = new ShellUtil(host.getHostIp(), host.getAccount(), host.getPassword(), host.getHostPort());
			
			cmd = String.format("cd %s && rm -rf docker-%s", remote, dockerVersion);
			result = execute.executeForResult(cmd);
			logger.info("\n清除docker历史安装目录 0 cmd ：{}" , cmd);
			
			//将安装文件压缩包分发到集群各主机
			JScpUtil.upload(host, local, remote);
			
			cmd = String.format("cd %s && tar -zxvf %s && rm -rf %s", remote,fileName,fileName);
			result = execute.executeForResult(cmd);
			logger.info("\n解压安装包 1 cmd ：{}" , cmd);
			
			cmd = String.format("cd %s && chmod 755 %s", appHome,shName);
			result = execute.executeForResult(cmd);
			logger.info("\n安装脚本授权755 2 cmd ：{}" , cmd);
			
			cmd = String.format("cd %s && ./%s", appHome,shName);
			result = execute.executeForResult(cmd);
			logger.info("\n安装执行{}安装docker 3 cmd ：{}" , shName,cmd);
			
			cmd = "docker -v";
			result = execute.executeForResult(cmd);
			logger.info("\n验证docker安装并写入应用库 ：执行{} \n返回 ：{}\n" , cmd,result);
			
			Integer appCount = appMapper.queryByNameAndIpCount(app);
			logger.info("\n docker应用统计： {}\n" , appCount);
			if(Validate.dockerIsInstall(host) && appCount<1) {
				app.setAppDockerPath(appHome);
				app.setAppFlag(1);
				appMapper.addApp(app);
			}
			logger.info("\n插入数据到应用表 ：{}" , result);
			execute.close();

		}
		return ResultWrapper.successResult();

	}
	
	/**
	 * <h2>删除应用</h2>
	 * <p><h3>分为二步</h3>
	 * <ul>
	 * <ol>
	 * <li>删除主机安装的应用</li>
	 * <li>使用脚本卸载docker吗?</li>
	 * <li>删除sqlite记录</li>
	 * </ol>
	 * </ul>
	 * </p>
	 * */
	@DeleteMapping("/del/app")
	public ResultWrapper delApp(@RequestBody List<Integer> ids) {
		List<App> hosts=new ArrayList<App>();
		App app = null;
		for (Integer id : ids) {
			app = new App();
			app.setId(id);
			hosts.add(app);
		}
		appMapper.deleteApps(hosts);
		return ResultWrapper.successResult(hosts);

	}
	
	/**
	 * <h2> 替换模板中baseurl的httpd地址 </h2>
	 * @return
	 */
	private String replaceRepoTemplateCmd(String httpdHostIp) {
		return String.format("find . -type f -name '*' | xargs perl -pi -e 's|hdp1.ambari|%s|g'",httpdHostIp);
	}
	
	/**
	 * <h2>设置系统-同步 yum源</h2>
	 * <p>
	 * <ul><ol>
	 * <li>同步yum的安装源到集群主机/etc/yum.repos.d/目录下</li>
	 * <li>执行yum clean all && yum makecache</li>
	 * </ol>
	 * </ul>
	 * </p>
	 * @author flash aGuang flash8627@hotmail.com 8538191@qq.com 2023/07/14
	 * @throws IOException 
	 * @throws ParseException 
	 *
	 */
	private ResultWrapper synYum(SSHClientVO clientVO) throws IOException {
		//开始拷贝安装源及yum repo -->
		logger.info("\nlocal Address:{}\nRemoteAddress:{}\n" ,clientVO.getLocalAddress(),clientVO.getRemoteAddress());
		ServerHost server = serverHostMapper.queryHostByIp(clientVO.getLocalAddress());
		logger.info("\nserver:{}\n" ,server.toString());
		ShellUtil execute = new ShellUtil(server.getHostIp(), server.getAccount(), server.getPassword(), server.getHostPort());
		
		final String remote = "/opt";
		final String repoFodName = "yum.repos.d";
		final String templateFodName = repoFodName+"_template";
		final String templateFileName = templateFodName+".tar.gz";
		
		//进入workHome解压repo模板,清理repoFodName目录和repoFodName.tar.gz,重新解压templateFileName,重命名templateFodName为repoFodName
		String cmd = String.format("cd %s/yum-pkg/ && rm -rf %s %s.tar.gz && tar -zxvf %s && mv %s %s",workHome,repoFodName,repoFodName,templateFileName,templateFodName,repoFodName);
		String result = execute.executeForResult(cmd);
		logger.info("\n检查CD本机yum-pkg目录{}下文件是否已经解压  ：{} \n返回：{}\n" ,workHome, cmd,result);
		
		//替换baseurl为主机IP
		cmd = String.format("cd %s/yum-pkg/%s/ && %s ",workHome,repoFodName,replaceRepoTemplateCmd(clientVO.getRemoteAddress()));
		result = execute.executeForResult(cmd);
		logger.info("\n检查/yum-pkg/yum.repos.d/下模板是否已经被替换 ：{}\n返回：{}\n" , cmd,result);
		
		//从新打包便于分发到其它主机,打包完了清理目录
		cmd = String.format("cd %s/yum-pkg/ && tar -zcvf %s.tar.gz %s && rm -rf %s",workHome,repoFodName,repoFodName,repoFodName);
		result = execute.executeForResult(cmd);
		logger.info("\n检查/yum-pkg/yum.repos.d压缩成功否 ：{}\n返回：{}\n" , cmd,result);
		
		server.setYumFlag(1);
		serverHostMapper.updateAppStatus(server);
		//将yum.repo.d分发到所有主机
		List<ServerHost> servers=serverHostMapper.queryHostList();
		for(ServerHost host : servers) {
			String yumPkgPath = String.format("%s/yum-pkg/%s.tar.gz", workHome,repoFodName);
			logger.info("\n{}分发 repo到主机 ：{} 目录{}\n",yumPkgPath,host.getHostIp(),remote);
			execute = new ShellUtil(host.getHostIp(), host.getAccount(), host.getPassword(), host.getHostPort());
			
			//备份yum.repos.d
			cmd = String.format("\\cp /etc/yum.repos.d /root/repo.%s.bak",DateUtil.getDateToString());
			logger.info("\n分发 repo到主机指令 ：{}\n",cmd);
			result = execute.executeForResult(cmd);
			
			//解压后清理压缩包,将配置文件拷贝到/etc/yum.repos.d/,如果文件存在则直接覆盖(\cp命令)
			cmd = String.format("rm -rf /etc/yum.repos.d/* && rm -rf /opt/yum.repos.d");
			logger.info("\n分发 repo到主机指令 ：{}\n",cmd);
			result = execute.executeForResult(cmd);
			
			//分发repo文件到各主机
			JScpUtil.upload(host, yumPkgPath, remote);
			
			cmd = String.format("cd %s && tar -zxvf %s.tar.gz && rm -rf %s.tar.gz && \\cp -rf %s/*.repo /etc/yum.repos.d/", remote,repoFodName,repoFodName,repoFodName);
			logger.info("\n分发 repo到主机指令 ：{}\n",cmd);
			result = execute.executeForResult(cmd);
			
			//清理yum重新构建 
			cmd = "yum clean all && yum makecache";
			result = execute.executeForResult(cmd);
			
			host.setYumFlag(1);
			serverHostMapper.updateAppStatus(host);
			
			execute.close();
			
		}
		execute = new ShellUtil(server.getHostIp(), server.getAccount(), server.getPassword(), server.getHostPort());
		cmd = String.format("cd %s/yum-pkg/ && rm -rf %s %s.tar.gz",workHome,repoFodName,repoFodName);
		result = execute.executeForResult(cmd);
		logger.info("\n清除repo文件 ：{}\n",cmd);
		
		return ResultWrapper.successResult();
	}
	
	/**
	 *  <h2>安装mysql或httpd主机 hosts</h2>
	 */
	private void installHosts(String ip,String type) throws Exception {

		String localIp = LinuxIPUtil.getLinuxLocalIp();
		logger.info("\n->>>>>>>>>>>>>>>>>>local IP:{}\n",localIp);

		String hostName = "mysql";
		if(type.equals(AppConstruct.HTTPD_APP)){
			hostName = "httpd";
		}
		/*if(type.equals(AppConstruct.AMBARI_SERVER)){
			hostName = "server";
		}*/

		String cmd = "";
		final String fileName = "hosts.sh";
		final String templateName = String.format("%s-template", fileName);
		final String local = String.format("%s/shell/%s", workHome,templateName);
		String result = null;
		ServerHost server=serverHostMapper.queryHostByIp(localIp);
		ShellUtil execute = new ShellUtil(server);
		logger.info("\n->>>>>>>>>>>>>>>>>>      IP:{}\n",ip);

		//覆盖拷贝
		cmd = String.format("\\cp -rf %s/shell/%s-src %s", workHome,fileName,local);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>>script copy cmd:{}\n",cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n->>>>>>>>>>>>>>>>>>script copy result:{}\n",result);

		//替换验证的IP
		cmd = String.format("sed -i 's/template_ip/%s/g' %s", ip,local);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>>>>>>>>hosts cmd:{}\n",cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>hosts cmd result:{}\n",result);

		//替换验证的主机名
		cmd = String.format("sed -i 's/template_hostname/%s.ambari/g' %s", hostName,local);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>>>>>>>>hosts cmd:{}\n",cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>>hosts cmd result:{}\n",result);

		cmd = String.format("sed -i '8i%s %s.ambari %s' %s",ip,hostName,hostName, local);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>>>>sed hosts cmd:{}\n",cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n->>>>>>>>>>>>>>>>sed hosts cmd result:{}\n",result);

		List<ServerHost> records = serverHostMapper.queryHostList();

		for (ServerHost host : records) {
			JScpUtil.upload(host, local, "/tmp");

			execute = new ShellUtil(host);
			cmd = String.format("\\cp -rf /tmp/%s /opt/%s", templateName,fileName);
			logger.info("\n hosts cmd:{}\n",cmd);
			// 执行命令
			result = execute.executeForResult(cmd);

			cmd = String.format("chmod o+x /opt/%s && /opt/%s", fileName, fileName);
			logger.info("\n 执行脚本文件:{}\n",cmd);
			result = execute.executeForResult(cmd);
			logger.info("\n hosts result:{}\n",result);

			cmd = String.format("rm -rf /tmp/%s /opt/%s", templateName,fileName);
			logger.info("\n->>>>>>>>>>>>>>>>>>>>>>>sed hosts cmd:{}\n",cmd);
			result = execute.executeForResult(cmd);

			execute.close();

		}

		execute = new ShellUtil(server);
		cmd = String.format("rm -rf %s", local);
		logger.info("\n->>>>>>>>>>>>>>>>>>>>>>>sed hosts cmd:{}\n",cmd);
		result = execute.executeForResult(cmd);
		logger.info("\n{}\n",result);

	}
}
